home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.3d26 source / Mac Telnet / TCP⁄IP / util.c < prev   
Text File  |  1989-09-26  |  24KB  |  1,043 lines

  1. /*
  2. *   Util.c
  3. *   utility library for use with the Network kernel
  4. *
  5. *   version 2, full session layer, TK started 6/17/87
  6. *
  7. ****************************************************************************
  8. *                                                                          *
  9. *      part of:                                                            *
  10. *      Network kernel for NCSA Telnet                                      *
  11. *      by Tim Krauskopf                                                    *
  12. *                                                                          *
  13. *      National Center for Supercomputing Applications                     *
  14. *      152 Computing Applications Building                                 *
  15. *      605 E. Springfield Ave.                                             *
  16. *      Champaign, IL  61820                                                *
  17. *                                                                          *
  18. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  19. *                                                                          *
  20. ****************************************************************************
  21. */
  22. #include "stdio.h"
  23. #include "whatami.h"
  24. #include "hostform.h"
  25.  
  26. #ifdef PC
  27. #include "string.h"
  28. #else
  29. char *index();
  30. #ifdef AZTEC
  31. #define strchr(A,B) index(A,B)
  32. #endif
  33. #endif
  34.  
  35. char                             /* special function types */
  36.             *neterrstring(),
  37.             *malloc();
  38. int32 time();                    /* don't forget this sucker! */
  39.  
  40. extern struct machinfo *Sns;
  41.  
  42. static unsigned char
  43.             *Ssstemps[] = {
  44.             "capfile",
  45.             "hp.out",
  46.             "ps.out",
  47.             "tek.out"
  48.             };
  49.  
  50. char Sptypes[NPORTS];        /* port types assigned for session use */
  51.  
  52.  
  53. extern struct config Scon;        /* hardware configuration */
  54.  
  55. #define NTIMES 30
  56.  
  57. /*
  58. *  timer queue of events which will be placed into the event queue
  59. *  when the time is up.
  60. */
  61. struct {
  62.     unsigned char
  63.         eclass,                    /* event queue data */
  64.         event;
  65.     int
  66.         next,                    /* next item in list */
  67.         idata;
  68.     int32 when;                /* when timer is to go off */
  69. } Stq[NTIMES];
  70.  
  71. static int
  72.         domwait = 0,            /* is domain waiting for nameserver? */
  73.         Stfirst,Stfree;            /* pointers for timer queue */
  74.         
  75. extern int domport();        /* return UDP port for name resolution */
  76.  
  77. #define PFTP 1
  78. #define PRCP 2
  79. #define PDATA 3
  80. #define PDOMAIN 4
  81.  
  82. /************************************************************************/
  83. /*  Snetinit
  84. *   Do network initialization for those who want the defaults all
  85. *   set for them.  Recommend that neterrchange be called before
  86. *   initializing network stuff.
  87. */
  88. Snetinit()
  89.     {
  90.     int i;
  91.  
  92. /*
  93. *  set up the file names
  94. */
  95.     Scon.capture = Ssstemps[0];
  96.     Scon.hpfile = Ssstemps[1];
  97.     Scon.psfile = Ssstemps[2];
  98.     Scon.tekfile = Ssstemps[3];
  99.  
  100.     neteventinit();                /* initializes for error messages to count */
  101.  
  102.     for (i=0; i<NPORTS; i++)
  103.         Sptypes[i] = -1;            /* clear port type flags */
  104.  
  105.     for (i=0; i<NTIMES; i++)
  106.         Stq[i].next = i+1;            /* load linked list */
  107.     Stq[NTIMES-1].next = -1;        /* anchor end */
  108.     Stfirst = -1;
  109.     Stfree = 0;
  110.  
  111.     if (!Sreadhosts()) {             /* parses config file */
  112. #ifdef PC
  113.         netparms(Scon.irqnum,Scon.address,Scon.ioaddr);
  114. #endif
  115.         netconfig(Scon.hw);
  116.  
  117.         if (!netinit()) {            /* starts up hardware */
  118. /*
  119. *  Check for the need to RARP and do it
  120. */
  121.             netgetip(Scon.myipnum);    /* get stored ip num */
  122.             if (comparen(Scon.myipnum,"RARP",4)) {    /* need RARP */
  123.                 if (netgetrarp())    /* stores in nnipnum at lower layer */
  124.                     return(-2);
  125.                 netgetip(Scon.myipnum);
  126.                 netsetip(Scon.myipnum);    
  127.             }
  128.  
  129. /*
  130. *  Give the lower layers a chance to check to see if anyone else
  131. *  is using the same ip number.  Usually generates an ARP packet.
  132. */
  133.             netarpme(Scon.myipnum);        
  134.  
  135.             Ssetgates();            /* finishes IP inits */
  136.             Stask();
  137.             return(0);
  138.         }
  139.     }
  140.  
  141.     return(-1);    
  142. }
  143.  
  144. /**************************************************************************/
  145. /*  Snetopen
  146. *
  147. *   Takes a pointer to a machine record, looked up with Sgethost and
  148. *   initiates the TCP open call.
  149. *
  150. */
  151. Snetopen(m,tport)
  152.     struct machinfo *m;
  153.     int tport;
  154.     {
  155.     int j;
  156.  
  157.     if (!m || m->mstat < HAVEIP)
  158.         return(-1);
  159.  
  160.     j = netxopen(m->hostip,tport,m->retrans,m->mtu,m->maxseg,m->window);
  161.                                     /* do the open call */
  162.  
  163.     if (j >= 0) {
  164.         Sptypes[j] = -1;            /* is allocated to user */
  165.         Stimerset(CONCLASS,CONFAIL,j,m->conto);
  166.         Stimerset(SCLASS,RETRYCON,j,m->retrans/TICKSPERSEC+2);
  167.     }
  168.  
  169.     return(j);
  170. }
  171.  
  172.  
  173. /**************************************************************************/
  174. /*
  175. *  special domain data structures
  176. */
  177. #define DOMSIZE 512                /* maximum domain message size to mess with */
  178.  
  179. /*
  180. *  Header for the DOMAIN queries
  181. *  ALL OF THESE ARE BYTE SWAPPED QUANTITIES!
  182. *  We are the poor slobs who are incompatible with the world's byte order
  183. */
  184. struct dhead {
  185. uint16
  186.     ident,                /* unique identifier */
  187.     flags,    
  188.     qdcount,            /* question section, # of entries */
  189.     ancount,            /* answers, how many */
  190.     nscount,            /* count of name server RRs */
  191.     arcount;            /* number of "additional" records */
  192. };
  193.  
  194. /*
  195. *  flag masks for the flags field of the DOMAIN header
  196. */
  197. #define DQR        0x8000            /* query = 0, response = 1 */
  198. #define DOPCODE    0x7100            /* opcode, see below */
  199. #define DAA        0x0400            /* Authoritative answer */
  200. #define DTC        0x0200            /* Truncation, response was cut off at 512 */
  201. #define DRD        0x0100            /* Recursion desired */
  202. #define DRA        0x0080            /* Recursion available */
  203. #define DRCODE    0x000F            /* response code, see below */
  204.  
  205.                                 /* opcode possible values: */
  206. #define DOPQUERY    0            /* a standard query */
  207. #define DOPIQ        1            /* an inverse query */
  208. #define DOPCQM        2            /* a completion query, multiple reply */
  209. #define DOPCQU        3             /* a completion query, single reply */
  210. /* the rest reserved for future */
  211.  
  212.                                 /* legal response codes: */
  213. #define DROK    0                /* okay response */
  214. #define DRFORM    1                /* format error */
  215. #define DRFAIL    2                /* their problem, server failed */
  216. #define DRNAME    3                /* name error, we know name doesn't exist */
  217. #define DRNOPE    4                /* no can do request */
  218. #define DRNOWAY    5                /* name server refusing to do request */
  219.  
  220. #define DTYPEA    1                /* host address resource record (RR) */
  221. #define DTYPEPTR    12            /* a domain name ptr */
  222.  
  223. #define DIN        1                /* ARPA internet class */
  224. #define DWILD    255                /* wildcard for several of the classifications */
  225.  
  226. /*
  227. *  a resource record is made up of a compressed domain name followed by
  228. *  this structure.  All of these ints need to be byteswapped before use.
  229. */
  230. struct rrpart {
  231.     uint16
  232.         rtype,                    /* resource record type = DTYPEA */
  233.         rclass;                    /* RR class = DIN */
  234.     uint32
  235.         rttl;                    /* time-to-live, changed to 32 bits */
  236.     uint16
  237.         rdlength;                /* length of next field */
  238.     uint8
  239.         rdata[DOMSIZE];            /* data field */
  240. };
  241.  
  242. /*
  243. *  data for domain name lookup
  244. */
  245. struct useek {
  246.     struct dhead h;
  247.     uint8 x[DOMSIZE];
  248. } question;
  249.  
  250. qinit()
  251.     {
  252.     question.h.flags = intswap(DRD);
  253.     question.h.qdcount = intswap(1);
  254.     question.h.ancount = 0;
  255.     question.h.nscount = 0;
  256.     question.h.arcount = 0;
  257. }
  258.  
  259.  
  260. /*********************************************************************/
  261. /*  packdom
  262. *   pack a regular text string into a packed domain name, suitable
  263. *   for the name server.
  264. */
  265. packdom(dst,src)
  266.     char *src,*dst;
  267.     {
  268.     char *p,*q,*savedst;
  269.     int i,dotflag,defflag;
  270.  
  271.     p = src;
  272.     dotflag = defflag = 0;
  273.     savedst = dst;
  274.  
  275.     do {                            /* copy whole string */
  276.         *dst = 0;
  277.         q = dst + 1;
  278.  
  279. /*
  280. *  copy the next label along, char by char until it meets a period or
  281. *  end of string.
  282. */
  283.         while (*p && (*p != '.')) 
  284.             *q++ = *p++;
  285.  
  286.         i = p - src;
  287.         if (i > 0x3f)
  288.             return(-1);
  289.         *dst = i;
  290.         *q = 0;
  291.  
  292.         if (*p) {                    /* update pointers */
  293.             dotflag = 1;
  294.             src = ++p;
  295.             dst = q;
  296.         }
  297.         else if (!dotflag && !defflag && Scon.defdom) {
  298.             p = Scon.defdom;        /* continue packing with default */
  299.             defflag = 1;
  300.             src = p;
  301.             dst = q;
  302.             netposterr(801);        /* using default domain */
  303.         }
  304.  
  305.     } while (*p);
  306.  
  307.     q++;
  308.     return(q-savedst);            /* length of packed string */
  309. }
  310.  
  311. /*********************************************************************/
  312. /*  unpackdom
  313. *  Unpack a compressed domain name that we have received from another
  314. *  host.  Handles pointers to continuation domain names -- buf is used
  315. *  as the base for the offset of any pointer which is present.
  316. *  returns the number of bytes at src which should be skipped over.
  317. *  Includes the NULL terminator in its length count.
  318. */
  319. unpackdom(dst,src,buf)
  320.     char *src,*dst,buf[];
  321.     {
  322.     int i,j,retval;
  323.     char *savesrc;
  324.  
  325.     savesrc = src;
  326.     retval = 0;
  327.  
  328.     while (*src) {
  329.         j = *src;
  330.  
  331.         while ((j & 0xC0) == 0xC0) {
  332.             if (!retval)
  333.                 retval = src-savesrc+2;
  334.             src++;
  335.             src = &buf[(j & 0x3f)*256+*src];        /* pointer dereference */
  336.             j = *src;
  337.         }
  338.  
  339.         src++;
  340.         for (i=0; i < (j & 0x3f) ; i++)
  341.             *dst++ = *src++;
  342.  
  343.         *dst++ = '.';
  344.     }
  345.  
  346.     *(--dst) = 0;            /* add terminator */
  347.     src++;                    /* account for terminator on src */
  348.  
  349.     if (!retval)
  350.         retval = src-savesrc;
  351.  
  352.     return(retval);
  353. }
  354.  
  355. /*********************************************************************/
  356. /*  sendom
  357. *   put together a domain lookup packet and send it
  358. *   uses port 53
  359. */
  360. sendom(s,towho,num)
  361.     char *s,*towho;
  362.     int16 num;
  363.     {
  364.     uint16 i,j,ulen;
  365.     uint8 *psave,*p;
  366.  
  367.     psave = (uint8 *)question.x;
  368.  
  369.     i = packdom(question.x,s);
  370.  
  371. /*
  372. *  load the fields of the question structure a character at a time so
  373. *  that 68000 machines won't barf.
  374. */
  375.     p = &question.x[i];
  376.     *p++ = 0;                /* high byte of qtype */
  377.     *p++ = DTYPEA;            /* number is < 256, so we know high byte=0 */
  378.     *p++ = 0;                /* high byte of qclass */
  379.     *p++ = DIN;                /* qtype is < 256 */
  380.  
  381.     question.h.ident = intswap(num);
  382.     ulen = sizeof(struct dhead)+(p-psave);
  383.  
  384.     netusend(towho,53,domport(),&question,ulen);
  385.     
  386. }
  387.  
  388. /**************************************************************************/
  389. /*  Sdomain
  390. *   DOMAIN based name lookup
  391. *   query a domain name server to get an IP number
  392. *    Returns the machine number of the machine record for future reference.
  393. *   Events generated will have this number tagged with them.
  394. *   Returns various negative numbers on error conditions.
  395. */
  396. Sdomain(mname)
  397.     char *mname;
  398.     {
  399.     struct machinfo *m;
  400.  
  401.     if (!Sns)                             /* no nameserver, give up now */
  402.         return(-1);
  403.  
  404.     while (*mname && *mname < 33)        /* kill leading spaces */
  405.         mname++;
  406.     if (!(*mname))
  407.         return(-1);
  408.  
  409.     if (!(m = Smadd(mname)))
  410.         return(-1);                        /* adds the number to the machlist */
  411.  
  412.     if (domwait < Scon.domto)
  413.         domwait = Scon.domto;            /* set the minimum timeout */
  414.  
  415.     qinit();                            /* initialize some flag fields */
  416.  
  417.     netulisten(domport());            /* pick a return port */
  418.     if (!m->hname)
  419.         m->hname = m->sname;            /* copy pointer to sname */
  420.  
  421.     sendom(m->hname,Sns->hostip,m->mno);    /* try UDP */
  422.  
  423.     Stimerset(SCLASS,UDPTO,m->mno,domwait);    /* time out quickly first time */
  424.     m->mstat = UDPDOM;
  425.  
  426.     return(m->mno);
  427.  
  428. }
  429.  
  430. /*********************************************************************/
  431. /*  getdomain
  432. *   Look at the results to see if our DOMAIN request is ready.
  433. *   It may be a timeout, which requires another query.
  434. */
  435.  
  436. udpdom()
  437.     {
  438.     struct machinfo *m;
  439.     int i,uret,num;
  440.     char *p;
  441.  
  442.     uret = neturead(&question);
  443.  
  444.     if (uret < 0) {
  445. /*        netputevent(USERCLASS,DOMFAIL,-1);  */
  446.         return(-1);
  447.     }
  448.  
  449.     num = intswap(question.h.ident);        /* get machine number */
  450. /*
  451. *  check to see if the necessary information was in the UDP response
  452. */
  453.     m = Slooknum(num);                /* get machine info record */
  454.     if (!m) {
  455.         netputevent(USERCLASS,DOMFAIL,num);
  456.         return(-1);
  457.     }
  458.  
  459. /*
  460. *  got a response, so reset timeout value to recommended minimum
  461. */
  462.     domwait = Scon.domto;
  463.  
  464.     i = ddextract(&question,m->hostip);
  465.  
  466.     switch (i) {
  467.         case 3:                        /* name does not exist */
  468.             netposterr(802);
  469.             p = neterrstring(-1);
  470.             strncpy(p,m->hname,78);        /* what name */
  471.             netposterr(-1);
  472.             netputevent(USERCLASS,DOMFAIL,num);
  473.             Stimerunset(SCLASS,UDPTO,num);
  474.             return(-1);
  475.         case 0:                        /* we found the IP number */
  476.             Stimerunset(SCLASS,UDPTO,num);
  477.             m->mstat = DOM;            /* mark that we have it from DOMAIN */
  478.             netputevent(USERCLASS,DOMOK,num);
  479.             return(0);
  480.         case -1:                    /* strange return code from ddextract */
  481.             netposterr(803);
  482.             break;
  483.         default:
  484.             netposterr(804);
  485.             break;
  486.     }
  487.  
  488.     return(0);
  489.  
  490. }
  491.  
  492. /**************************************************************************/
  493. /*  domto
  494. *   Handle time out for DOMAIN name lookup
  495. *   Retry as many times as recommended by config file
  496. */
  497. domto(num)
  498.     int num;
  499.     {
  500.     struct machinfo *m;
  501.  
  502.     m = Slooknum(num);
  503.     if (!m)
  504.         return(-1);
  505.  
  506.     if (m->mstat > UDPDOM + Scon.ndom) {    /* permanent timeout */
  507.         netputevent(USERCLASS,DOMFAIL,num);
  508.         return(-1);
  509.     }
  510.     else
  511.         m->mstat++;            /* one more timeout */
  512.     
  513.     if (domwait < 20)        /* exponential backoff */
  514.         domwait <<= 1;
  515.  
  516.     Snewns();                /* rotate to next nameserver */
  517.  
  518.     qinit();
  519.  
  520.     netulisten(domport());            /* pick a return port */
  521.     sendom(m->hname,Sns->hostip,num);        /* try UDP */
  522.  
  523.     Stimerset(SCLASS,UDPTO,num,domwait);    /* time out more slowly */
  524.  
  525.     return(num);
  526.     
  527. }
  528.  
  529. /*********************************************************************/
  530. /*  ddextract
  531. *   extract the ip number from a response message.
  532. *   returns the appropriate status code and if the ip number is available,
  533. *   copies it into mip
  534. */
  535. ddextract(qp,mip)
  536.     struct useek *qp;
  537.     unsigned char *mip;
  538.     {
  539.     uint16 i,j,nans,rcode;
  540.     struct rrpart *rrp;
  541.     uint8 *p,space[260];
  542.  
  543.     nans = intswap(qp->h.ancount);                /* number of answers */
  544.     rcode = DRCODE & intswap(qp->h.flags);        /* return code for this message*/
  545.     if (rcode > 0)
  546.         return(rcode);
  547.  
  548.     if (nans > 0 &&                                /* at least one answer */
  549.         (intswap(qp->h.flags) & DQR)) {            /* response flag is set */
  550.         p = (uint8 *)qp->x;                    /* where question starts */
  551.         i = unpackdom(space,p,qp);                /* unpack question name */
  552. /*  spec defines name then  QTYPE + QCLASS = 4 bytes */
  553.         p += i+4;
  554. /*
  555. *  at this point, there may be several answers.  We will take the first
  556. *  one which has an IP number.  There may be other types of answers that
  557. *  we want to support later.
  558. */
  559.         while (nans-- > 0) {                    /* look at each answer */
  560.             i = unpackdom(space,p,qp);            /* answer name to unpack */
  561. /*            n_puts(space);*/
  562.             p += i;                                /* account for string */
  563.             rrp = (struct rrpart *)p;            /* resource record here */
  564. /*
  565. *  check things which might not align on 68000 chip one byte at a time
  566. */
  567.             if (!*p && *(p+1) == DTYPEA &&         /* correct type and class */
  568.                 !*(p+2) && *(p+3) == DIN) {
  569.                 movebytes(mip,rrp->rdata,4);    /* save IP #         */
  570.                 return(0);                        /* successful return */
  571.             }
  572.             movebytes(&j,&rrp->rdlength,2);        /* 68000 alignment */
  573.             p += 10+intswap(j);                    /* length of rest of RR */
  574.         }
  575.     }
  576.  
  577.     return(-1);                        /* generic failed to parse */
  578. }
  579.  
  580.  
  581. /***********************************************************************/
  582. static int son=1;
  583.  
  584. Scwritemode(mode)
  585.     int mode;
  586.     {
  587.         son = mode;
  588.         return(0);
  589. }
  590.  
  591. /***********************************************************************/
  592. Scmode()
  593.     {
  594.     return(son);
  595. }
  596.  
  597. /***********************************************************************/
  598. static int tekon=1;
  599.  
  600. Stekmode(mode)
  601.     int mode;
  602.     {
  603.         tekon = mode;
  604.         return(0);
  605. }
  606.  
  607. /***********************************************************************/
  608. Stmode()
  609.     {
  610.     return(tekon);
  611. }
  612.  
  613. /***********************************************************************/
  614. #ifdef PC
  615. static int rcpon=1;
  616.  
  617. Srcpmode(mode)
  618.     int mode;
  619.     {
  620.         rcpon = mode;
  621.         if (rcpon)
  622.             setrshd();
  623.         else
  624.             unsetrshd();
  625.         return(0);
  626. }
  627.  
  628. /***********************************************************************/
  629. Srmode()
  630.     {
  631.     return(rcpon);
  632. }
  633. #endif
  634.  
  635. /***********************************************************************/
  636. static int ftpon=0;
  637.  
  638. Sftpmode(mode)
  639.     int mode;
  640.     {
  641.         if (ftpon && mode)
  642.             return(-1);
  643.  
  644.         ftpon = mode;
  645.         if (ftpon)
  646.             setftp();
  647.         else
  648.             unsetftp();
  649.         return(0);
  650. }
  651.  
  652. /***********************************************************************/
  653. Sfmode()
  654.     {
  655.     return(ftpon);
  656. }
  657.  
  658. /***********************************************************************/
  659. /*  Snewcap
  660. *   set a new capture file name
  661. */
  662. Snewcap(s)
  663.     char *s;
  664.     {
  665.     if (NULL == (Scon.capture = malloc(strlen(s)+1)))
  666.         return(1);
  667.     strcpy(Scon.capture,s);
  668.     return(0);
  669. }
  670.  
  671. /***********************************************************************/
  672. /*  Snewps
  673. *   set a new ps file name
  674. */
  675. Snewpsfile(s)
  676.     char *s;
  677.     {
  678.     if (NULL == (Scon.psfile = malloc(strlen(s)+1)))
  679.         return(1);
  680.     strcpy(Scon.psfile,s);
  681.     return(0);
  682. }
  683.  
  684. /***********************************************************************/
  685. /*  Snewhpfile
  686. *   set a new HPGL file name
  687. */
  688. Snewhpfile(s)
  689.     char *s;
  690.     {
  691.     if (NULL == (Scon.hpfile = malloc(strlen(s)+1)))
  692.         return(1);
  693.     strcpy(Scon.hpfile,s);
  694.     return(0);
  695. }
  696.  
  697. /***********************************************************************/
  698. /*  Snewtekfile
  699. *   set a new tek file name
  700. */
  701. Snewtekfile(s)
  702.     char *s;
  703.     {
  704.     if (NULL == (Scon.tekfile = malloc(strlen(s)+1)))
  705.         return(1);
  706.     strcpy(Scon.tekfile,s);
  707.     return(0);
  708. }
  709.  
  710. /***********************************************************************/
  711. /*  Sopencap
  712. *   returns a file handle to an open capture file
  713. *   Uses the locally stored capture file name.
  714. */
  715. FILE *
  716. Sopencap()
  717.     {
  718.     FILE *retfp;
  719.  
  720.     if (NULL == (retfp = fopen(Scon.capture,"ab"))) 
  721.         return(NULL);
  722.  
  723.     fseek(retfp,0L,2);        /* seek to end */
  724.  
  725.     return(retfp);
  726. }
  727.  
  728. /**************************************************************************/
  729. /*  Stask
  730. *   A higher level version of netsleep
  731. *
  732. *   This manages the timer queue
  733. */
  734.  
  735. static int32 recent=0L;
  736.  
  737. Stask()
  738.     {
  739.     long t;
  740.     int i;
  741.  
  742. #ifndef APPLE_DRIVERS
  743.     netsleep(0);
  744. #endif APPLE_DRIVERS
  745.  
  746. /*
  747. *  Check the timer queue to see if something should be posted
  748. *  First check for timer wraparound
  749. */
  750.     t = time(NULL);
  751. #ifdef PC
  752.     if (t < recent) {
  753.         i = Stfirst;
  754.         while (i >= 0) {
  755.             Stq[i].when -= WRAPTIME;
  756.             i = Stq[i].next;
  757.         }
  758.     }
  759. #endif
  760.     recent = t;                            /* save most recent time */
  761.  
  762.     while (Stfirst >= 0 && t > Stq[Stfirst].when) {        
  763.                                 /* Q is not empty and timer is going off */
  764.         i = Stfirst;
  765.         netputevent(Stq[i].eclass,Stq[i].event,Stq[i].idata);
  766.         Stfirst = Stq[Stfirst].next;    /* remove from q */
  767.         Stq[i].next = Stfree;
  768.         Stfree = i;                        /* add to free list */
  769.     }
  770.  
  771.  
  772. }
  773.  
  774. /**************************************************************************/
  775. /*  Stimerset
  776. *  Sets an asynchronous timer which is checked in Stask()
  777. *  usage:
  778. *  Time is in seconds
  779. *  Stimerset(class,event,dat,time)
  780. *    int class,event,dat,time;
  781. *    class,event,dat is the event which should be posted at the specified
  782. *    time.  Accuracy is dependent on how often Stask is called.
  783. */
  784.  
  785. Stimerset(class,event,dat,howlong)
  786.     int class,event,dat,howlong;
  787.     {
  788.     int i,j,jlast,retval;
  789.     int32 gooff;
  790.  
  791.     retval = 0;
  792.     gooff = time(NULL) + howlong;
  793.  
  794.     if (Stfree < 0) {                /* queue is full, post first event */
  795.         Stfree = Stfirst;
  796.         Stfirst = Stq[Stfirst].next;
  797.         Stq[Stfree].next = -1;
  798.         netputevent(Stq[Stfree].eclass,Stq[Stfree].event,Stq[Stfree].idata);
  799.         retval = -1;
  800.     }
  801.  
  802.     Stq[Stfree].idata = dat;                /* event to occur at that time */
  803.     Stq[Stfree].event = event;
  804.     Stq[Stfree].eclass = class;
  805.     Stq[Stfree].when = gooff;
  806.     i = Stfree;                            /* remove from free list */
  807.     Stfree = Stq[i].next;
  808.  
  809.     if (Stfirst < 0) {                    /* if no queue yet */
  810.         Stfirst = i;
  811.         Stq[i].next = -1;                /* anchor active q */
  812.     }
  813.  
  814.     else if (gooff < Stq[Stfirst].when) {    /* goes first on list */
  815.         Stq[i].next = Stfirst;                /* at beginning of list */
  816.         Stfirst = i;
  817.     }
  818.  
  819.     else {                                    /* goes in middle */
  820.  
  821.         j = jlast = Stfirst;                /* search q from beginning */
  822.  
  823.         while (gooff >= Stq[j].when && j >= 0) {
  824.             jlast = j;
  825.             j = Stq[j].next;
  826.         }
  827.         Stq[i].next = j;                    /* insert in q */
  828.         Stq[jlast].next = i;
  829.     }
  830.  
  831.     return(retval);
  832. }
  833.  
  834. /****************************************************************************/
  835. /*  Stimerunset
  836. *   Remove all such timer events from the queue
  837. *   They must match all three fields, event, class and optional data
  838. *
  839. */
  840. Stimerunset(class,event,dat)
  841.     unsigned char event,class;
  842.     int dat;
  843.     {
  844.     int i,ilast,retval;
  845.  
  846.     retval = ilast = -1;
  847.     i = Stfirst;
  848.     while (i >= 0 ) {                    /* search list */
  849.  
  850.         if (Stq[i].idata == dat &&         /* this one matches */
  851.             Stq[i].eclass == class && Stq[i].event == event) {
  852.  
  853.             retval = 0;                    /* found at least one */
  854. /*
  855. * major bug fix -- if first element matched, old code could crash
  856. */
  857.             if (i == Stfirst) {
  858.                 Stfirst = Stq[i].next;            /* first one matches */
  859.                 Stq[i].next = Stfree;            /* attach to free list */
  860.                 Stfree = i;
  861.                 i = Stfirst;
  862.                 continue;                        /* start list over */
  863.             }
  864.             else {
  865.                 Stq[ilast].next = Stq[i].next;    /* remove this entry */
  866.                 Stq[i].next = Stfree;            /* attach to free list */
  867.                 Stfree = i;
  868.                 i = ilast;
  869.             }
  870.         }
  871.  
  872.         ilast = i;
  873.         i = Stq[i].next;
  874.     }
  875.  
  876.     return(retval);
  877. }
  878.  
  879. /****************************************************************************/
  880. /*  Scheckpass
  881. *   Check the password file for the user,password combination
  882. *   Returns valid or invalid
  883. */
  884. Scheckpass(us,ps)
  885.     char *us,*ps;
  886.     {
  887.     char buf[81],*p;
  888.     FILE *fp;
  889.     int i;
  890.     
  891.     if (NULL == (fp = fopen(Scon.pass,"r"))) {
  892.     
  893. #ifdef MAC
  894. /*
  895. *  failed open, so try to find file in the system folder.
  896. */
  897.  
  898.         sysdir();                            /* change to system folder */
  899.         fp = fopen(Scon.pass,"r");
  900.         
  901.         setmydir();                            /* reset back to default dir */
  902.         
  903.         if (NULL == fp)                        /* still didn't work? */
  904. #endif
  905.             return(0);
  906.     }
  907.  
  908.     while (NULL != fgets(buf,80,fp)) {
  909.         p = strchr(buf,'\n');
  910.         *p = '\0';                            /* remove \n */
  911.  
  912.         p = strchr(buf,':');                /* find delimiter */
  913.         *p++ = '\0';
  914.         if (!strcmp(buf,us) &&            /* found user */
  915.             Scompass(ps,p)) {            /* does password check ?*/
  916.             fclose(fp);
  917.             return(1);
  918.         }
  919.     }
  920.  
  921.     fclose(fp);
  922.     return(0);
  923. }
  924.  
  925. /****************************************************************************/
  926. /* Sneedpass
  927. *  For other routines to call and find out if a password is required
  928. */
  929. Sneedpass()
  930.     {
  931.     if (Scon.pass == NULL)
  932.         return(0);
  933.  
  934.     return(1);
  935. }
  936.  
  937. /****************************************************************************/
  938. /* Scompass
  939. *  compute and check the encrypted password
  940. */
  941. Scompass(ps,en)
  942.     char *ps,*en;
  943.     {
  944.     int ck;
  945.     char *p,c;
  946.  
  947.     ck = 0;
  948.     p = ps;
  949.     while (*p)                /* checksum the string */
  950.         ck += *p++;
  951.  
  952.     c = ck;
  953.  
  954.     while (*en) {
  955.         if ((((*ps ^ c) | 32) & 127) != *en)    /* XOR with checksum */
  956.             return(0);
  957.         if (*ps)
  958.             ps++;
  959.         else
  960.             c++;            /* increment checksum to hide length */
  961.         en++;
  962.     }
  963.  
  964.     return(1);
  965. }
  966.  
  967. /****************************************************************************/
  968. /*  Sgetevent
  969. *   gets events from the network and filters those for session related
  970. *   activity.  Returns any other events to the caller.
  971. */
  972. Sgetevent(class,what,datp)
  973.     int class,*what,*datp;
  974.     {
  975.     int retval;
  976.  
  977.     if (retval = netgetevent(SCLASS,what,datp)) {    /* session event */
  978.         switch (retval) {
  979.             case FTPACT:
  980.                 ftpd(0,*datp);
  981.                 break;
  982. #ifdef PC
  983.             case RCPACT:                /* give CPU to rsh for rcp */
  984.                 rshd(0);
  985.                 break;
  986. #endif
  987. #ifdef MAC
  988.             case CLOSEDONE:                /* Used in the drivers */
  989.                 netclose( *datp);
  990.                 break;
  991.             case CLOSEDONE+1:                /* Used in the drivers */
  992.                 netclose( *datp);
  993.                 break;
  994. #endif MAC
  995.             case UDPTO:                    /* name server not responding */
  996.                 domto(*datp);
  997.                 break;
  998.             case RETRYCON:
  999.                 if (0 < netopen2(*datp))     /* connection open yet? */
  1000.                     Stimerset(SCLASS,RETRYCON,*datp,4);  /* 4 is a kludge */
  1001.                 break;
  1002.  
  1003.             default:
  1004.                 break;
  1005.         }
  1006.     }
  1007.  
  1008.     Stask();                        /* allow net and timers to take place */
  1009.  
  1010.     if (!(retval = netgetevent(class,what,datp)))
  1011.         return(0);
  1012.         
  1013.     if (retval == CONOPEN) 
  1014.         Stimerunset(CONCLASS,CONFAIL,*datp);   /* kill this timer */
  1015.  
  1016.     if ((*datp == domport()) && (retval == UDPDATA)) {
  1017.         udpdom();
  1018.     }
  1019.     else if ((*what == CONCLASS) && (Sptypes[*datp] >= 0)) {
  1020.                                         /* might be for session layer */
  1021.         switch (Sptypes[*datp]) {
  1022.             case PFTP:
  1023.                 rftpd(retval);
  1024.                 break;
  1025.             case PDATA:
  1026.                 ftpd(retval,*datp);
  1027.                 break;
  1028. #ifdef PC
  1029.             case PRCP:
  1030.                 rshd(retval);
  1031.                 break;
  1032. #endif
  1033.             default:
  1034.                 break;
  1035.         }
  1036.     }
  1037.     else
  1038.         return(retval);                /* let higher layer have it */
  1039.  
  1040.     return(0);
  1041. }
  1042.  
  1043.